<!DOCTYPE html>
<html lang="zh-CN">
  <head>
    <meta charset="UTF-8" />
    <meta name="viewport" content="width=device-width, initial-scale=1.0" />
    <title>用户会话录制与回放 - Session Replay</title>
    <!-- 
      用户会话录制与回放系统
      基于 rrweb 技术实现的前端用户行为录制和回放功能
      主要功能：
      1. 录制用户在页面上的所有操作（点击、输入、滚动等）
      2. 回放录制的用户操作，完整还原用户行为
      3. 支持样式保留，确保回放时视觉效果一致
      4. 提供友好的操作界面和状态反馈
    -->
    <style>
      /* 全局样式重置和基础设置 */
      * {
        margin: 0;
        padding: 0;
        box-sizing: border-box; /* 统一盒模型，便于布局计算 */
      }

      body {
        font-family: 'Segoe UI', Tahoma, Geneva, Verdana, sans-serif; /* 现代化字体栈 */
        background: linear-gradient(
          135deg,
          #667eea 0%,
          #764ba2 100%
        ); /* 渐变背景 */
        min-height: 100vh; /* 确保页面至少占满视口高度 */
        padding: 20px; /* 页面边距 */
      }

      /* 主容器样式 */
      .container {
        max-width: 1200px; /* 限制最大宽度，保持良好的阅读体验 */
        margin: 0 auto; /* 水平居中 */
        background: white; /* 白色背景 */
        border-radius: 20px; /* 圆角边框 */
        box-shadow: 0 20px 40px rgba(0, 0, 0, 0.1); /* 阴影效果 */
        overflow: hidden; /* 隐藏溢出内容 */
      }

      /* 页面头部样式 */
      .header {
        background: linear-gradient(
          135deg,
          #667eea 0%,
          #764ba2 100%
        ); /* 渐变背景 */
        color: white; /* 白色文字 */
        padding: 30px; /* 内边距 */
        text-align: center; /* 文字居中 */
      }

      .header h1 {
        font-size: 2.5em;
        margin-bottom: 10px;
        font-weight: 300;
      }

      .header p {
        font-size: 1.1em;
        opacity: 0.9;
      }

      .content {
        padding: 40px;
      }

      .section {
        margin-bottom: 40px;
        padding: 30px;
        background: #f8f9fa;
        border-radius: 15px;
        border-left: 5px solid #667eea;
      }

      .section h2 {
        color: #333;
        margin-bottom: 20px;
        font-size: 1.8em;
        font-weight: 500;
      }

      .controls {
        display: flex;
        gap: 15px;
        margin-bottom: 20px;
        flex-wrap: wrap;
      }

      /* 按钮基础样式 */
      .btn {
        padding: 12px 24px; /* 内边距 */
        border: none; /* 移除边框 */
        border-radius: 8px; /* 圆角 */
        cursor: pointer; /* 鼠标指针 */
        font-size: 16px; /* 字体大小 */
        font-weight: 500; /* 字体粗细 */
        transition: all 0.3s ease; /* 平滑过渡效果 */
        display: flex; /* 弹性布局 */
        align-items: center; /* 垂直居中 */
        gap: 8px; /* 图标和文字间距 */
      }

      /* 按钮悬停效果 */
      .btn:hover {
        transform: translateY(-2px); /* 向上移动 */
        box-shadow: 0 5px 15px rgba(0, 0, 0, 0.2); /* 阴影效果 */
      }

      /* 主要按钮样式（播放） */
      .btn-primary {
        background: linear-gradient(
          135deg,
          #667eea 0%,
          #764ba2 100%
        ); /* 蓝紫渐变 */
        color: white;
      }

      /* 成功按钮样式（开始录制） */
      .btn-success {
        background: linear-gradient(
          135deg,
          #56ab2f 0%,
          #a8e6cf 100%
        ); /* 绿色渐变 */
        color: white;
      }

      /* 危险按钮样式（停止录制） */
      .btn-danger {
        background: linear-gradient(
          135deg,
          #ff416c 0%,
          #ff4b2b 100%
        ); /* 红色渐变 */
        color: white;
      }

      /* 警告按钮样式（清空/暂停） */
      .btn-warning {
        background: linear-gradient(
          135deg,
          #f093fb 0%,
          #f5576c 100%
        ); /* 粉色渐变 */
        color: white;
      }

      /* 禁用按钮样式 */
      .btn:disabled {
        opacity: 0.6; /* 透明度降低 */
        cursor: not-allowed; /* 禁用鼠标指针 */
        transform: none; /* 移除变换效果 */
      }

      /* 状态显示基础样式 */
      .status {
        padding: 15px; /* 内边距 */
        border-radius: 8px; /* 圆角 */
        margin-bottom: 20px; /* 下边距 */
        font-weight: 500; /* 字体粗细 */
      }

      /* 录制中状态样式 */
      .status.recording {
        background: #d4edda; /* 浅绿背景 */
        color: #155724; /* 深绿文字 */
        border: 1px solid #c3e6cb; /* 绿色边框 */
      }

      /* 停止状态样式 */
      .status.stopped {
        background: #f8d7da; /* 浅红背景 */
        color: #721c24; /* 深红文字 */
        border: 1px solid #f5c6cb; /* 红色边框 */
      }

      /* 播放中状态样式 */
      .status.playing {
        background: #d1ecf1; /* 浅蓝背景 */
        color: #0c5460; /* 深蓝文字 */
        border: 1px solid #bee5eb; /* 蓝色边框 */
      }

      /* 回放容器样式 */
      .replay-container {
        margin-top: 20px; /* 上边距 */
        border: 2px solid #dee2e6; /* 边框 */
        border-radius: 10px; /* 圆角 */
        overflow: hidden; /* 隐藏溢出 */
        background: #fff; /* 白色背景 */
      }

      /* 回放目标区域样式 */
      .replay-target {
        width: 100%; /* 全宽 */
        height: 700px; /* 固定高度 */
        border: none; /* 无边框 */
        background: #f8f9fa; /* 浅灰背景 */
        overflow: hidden; /* 隐藏溢出 */
        position: relative; /* 相对定位 */
        padding-bottom: 85px; /* 底部内边距 */
      }

      .replay-target .rr-player {
        width: 100% !important;
        height: 100% !important;
      }

      .progress-container {
        padding: 20px;
        background: #f8f9fa;
        border-top: 1px solid #dee2e6;
      }

      .progress-bar {
        width: 100%;
        height: 8px;
        background: #e9ecef;
        border-radius: 4px;
        overflow: hidden;
        margin-bottom: 15px;
      }

      .progress-fill {
        height: 100%;
        background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
        width: 0%;
        transition: width 0.3s ease;
      }

      .time-info {
        display: flex;
        justify-content: space-between;
        align-items: center;
        font-size: 14px;
        color: #6c757d;
      }

      .events-info {
        background: #e9ecef;
        padding: 15px;
        border-radius: 8px;
        margin-top: 15px;
      }

      .events-info h3 {
        margin-bottom: 10px;
        color: #495057;
      }

      .icon {
        width: 16px;
        height: 16px;
      }

      .tech-notes {
        background: #fff3cd;
        border: 1px solid #ffeaa7;
        border-radius: 8px;
        padding: 20px;
        margin-top: 30px;
      }

      .tech-notes h3 {
        color: #856404;
        margin-bottom: 15px;
      }

      .tech-notes ul {
        color: #856404;
        padding-left: 20px;
      }

      .tech-notes li {
        margin-bottom: 8px;
      }

      /* 操作演示区域样式 */
      .demo-area {
        margin-bottom: 30px;
        padding: 20px;
        background: #ffffff;
        border-radius: 10px;
        border: 1px solid #e9ecef;
      }

      .demo-area h3 {
        color: #495057;
        margin-bottom: 15px;
        font-size: 1.3em;
        font-weight: 500;
      }

      /* 视频控制区域 */
      .video-controls {
        margin-bottom: 15px;
      }

      .file-input {
        display: none;
      }

      /* 交互控制区域 */
      .interactive-controls {
        display: flex;
        gap: 10px;
        margin-bottom: 20px;
        flex-wrap: wrap;
      }

      /* 输入区域 */
      .input-area {
        margin-bottom: 20px;
      }

      .test-input {
        width: 100%;
        max-width: 400px;
        padding: 10px;
        border: 2px solid #e9ecef;
        border-radius: 6px;
        font-size: 14px;
        margin-bottom: 10px;
        transition: border-color 0.3s ease;
      }

      .test-input:focus {
        outline: none;
        border-color: #667eea;
        box-shadow: 0 0 0 3px rgba(102, 126, 234, 0.1);
      }

      .test-textarea {
        width: 100%;
        max-width: 400px;
        height: 80px;
        padding: 10px;
        border: 2px solid #e9ecef;
        border-radius: 6px;
        font-size: 14px;
        resize: vertical;
        font-family: inherit;
        transition: border-color 0.3s ease;
      }

      .test-textarea:focus {
        outline: none;
        border-color: #667eea;
        box-shadow: 0 0 0 3px rgba(102, 126, 234, 0.1);
      }

      /* 复选框和单选框区域 */
      .checkbox-area {
        display: flex;
        flex-direction: column;
        gap: 10px;
        margin-bottom: 20px;
      }

      .checkbox-label,
      .radio-label {
        display: flex;
        align-items: center;
        gap: 8px;
        cursor: pointer;
        font-size: 14px;
        color: #495057;
      }

      .checkbox-label input,
      .radio-label input {
        cursor: pointer;
      }

      /* 选择框区域 */
      .select-area {
        margin-bottom: 20px;
      }

      .test-select {
        width: 100%;
        max-width: 300px;
        padding: 10px;
        border: 2px solid #e9ecef;
        border-radius: 6px;
        font-size: 14px;
        background: white;
        cursor: pointer;
        transition: border-color 0.3s ease;
      }

      .test-select:focus {
        outline: none;
        border-color: #667eea;
        box-shadow: 0 0 0 3px rgba(102, 126, 234, 0.1);
      }

      /* 滚动测试区域 */
      .scroll-area {
        height: 200px;
        overflow-y: auto;
        border: 2px solid #e9ecef;
        border-radius: 8px;
        padding: 15px;
        margin-bottom: 20px;
        background: #f8f9fa;
      }

      .scroll-area h4 {
        color: #495057;
        margin-bottom: 10px;
      }

      .scroll-area p {
        margin-bottom: 10px;
        color: #6c757d;
        line-height: 1.5;
      }

      /* 拖拽区域 */
      .drag-area {
        display: flex;
        gap: 20px;
        align-items: center;
        margin-bottom: 20px;
        flex-wrap: wrap;
      }

      .draggable-item {
        padding: 15px 20px;
        background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
        color: white;
        border-radius: 8px;
        cursor: move;
        user-select: none;
        transition: transform 0.2s ease;
        font-weight: 500;
      }

      .draggable-item:hover {
        transform: scale(1.05);
      }

      .draggable-item.dragging {
        opacity: 0.5;
        transform: rotate(5deg);
      }

      .drop-zone {
        min-width: 200px;
        min-height: 80px;
        border: 3px dashed #dee2e6;
        border-radius: 8px;
        display: flex;
        align-items: center;
        justify-content: center;
        color: #6c757d;
        font-weight: 500;
        transition: all 0.3s ease;
      }

      .drop-zone.drag-over {
        border-color: #667eea;
        background: rgba(102, 126, 234, 0.1);
        color: #667eea;
      }

      /* 操作日志区域 */
      .operation-log {
        height: 150px;
        overflow-y: auto;
        border: 2px solid #e9ecef;
        border-radius: 8px;
        padding: 15px;
        background: #f8f9fa;
        font-family: 'Courier New', monospace;
        font-size: 13px;
        line-height: 1.4;
      }

      .operation-log p {
        margin-bottom: 5px;
        color: #495057;
      }

      .operation-log .log-entry {
        margin-bottom: 3px;
        padding: 2px 0;
        border-bottom: 1px solid #e9ecef;
      }

      .operation-log .log-time {
        color: #6c757d;
        font-size: 11px;
      }

      .operation-log .log-action {
        color: #495057;
        font-weight: 500;
      }

      @media (max-width: 768px) {
        .controls {
          flex-direction: column;
        }

        .btn {
          justify-content: center;
        }

        .header h1 {
          font-size: 2em;
        }

        .content {
          padding: 20px;
        }

        .interactive-controls {
          flex-direction: column;
        }

        .drag-area {
          flex-direction: column;
          align-items: stretch;
        }

        .test-input,
        .test-textarea,
        .test-select {
          max-width: 100%;
        }
      }
    </style>
  </head>
  <body>
    <div class="container">
      <div class="header">
        <h1>🎬 用户会话录制与回放</h1>
        <p>基于 rrweb 技术的无感知前端录屏解决方案</p>
      </div>

      <div class="content">
        <!-- 录制控制区域 -->
        <div class="section">
          <h2>📹 录制控制</h2>
          <div class="status" id="recordStatus">
            准备就绪 - 点击开始录制按钮开始记录用户操作
          </div>

          <div class="controls">
            <button class="btn btn-success" id="startBtn">
              <svg class="icon" fill="currentColor" viewBox="0 0 20 20">
                <path
                  fill-rule="evenodd"
                  d="M10 18a8 8 0 100-16 8 8 0 000 16zM9.555 7.168A1 1 0 008 8v4a1 1 0 001.555.832l3-2a1 1 0 000-1.664l-3-2z"
                  clip-rule="evenodd"
                ></path>
              </svg>
              开始录制
            </button>

            <button class="btn btn-danger" id="stopBtn" disabled>
              <svg class="icon" fill="currentColor" viewBox="0 0 20 20">
                <path
                  fill-rule="evenodd"
                  d="M10 18a8 8 0 100-16 8 8 0 000 16zM8 7a1 1 0 00-1 1v4a1 1 0 001 1h4a1 1 0 001-1V8a1 1 0 00-1-1H8z"
                  clip-rule="evenodd"
                ></path>
              </svg>
              停止录制
            </button>

            <button class="btn btn-warning" id="clearBtn">
              <svg class="icon" fill="currentColor" viewBox="0 0 20 20">
                <path
                  fill-rule="evenodd"
                  d="M9 2a1 1 0 000 2h2a1 1 0 100-2H9z"
                  clip-rule="evenodd"
                ></path>
                <path
                  fill-rule="evenodd"
                  d="M10 18a8 8 0 100-16 8 8 0 000 16zm3.707-9.293a1 1 0 00-1.414-1.414L9 10.586 7.707 9.293a1 1 0 00-1.414 1.414L7.586 12l-1.293 1.293a1 1 0 101.414 1.414L9 13.414l1.293 1.293a1 1 0 001.414-1.414L10.414 12l1.293-1.293z"
                  clip-rule="evenodd"
                ></path>
              </svg>
              清空数据
            </button>
          </div>

          <div class="events-info">
            <h3>录制信息</h3>
            <p>已录制事件数量: <span id="eventCount">0</span></p>
            <p>录制时长: <span id="recordDuration">00:00</span></p>
          </div>
        </div>

        <!-- 视频回放区域 -->
        <div class="section">
          <h2>🎥 视频回放</h2>
          <div class="status" id="playStatus">
            暂无录制数据 - 请先进行录制操作
          </div>

          <div class="controls">
            <button class="btn btn-primary" id="playBtn" disabled>
              <svg class="icon" fill="currentColor" viewBox="0 0 20 20">
                <path
                  fill-rule="evenodd"
                  d="M10 18a8 8 0 100-16 8 8 0 000 16zM9.555 7.168A1 1 0 008 8v4a1 1 0 001.555.832l3-2a1 1 0 000-1.664l-3-2z"
                  clip-rule="evenodd"
                ></path>
              </svg>
              播放回放
            </button>

            <button class="btn btn-warning" id="pauseBtn" disabled>
              <svg class="icon" fill="currentColor" viewBox="0 0 20 20">
                <path
                  fill-rule="evenodd"
                  d="M18 10a8 8 0 11-16 0 8 8 0 0116 0zM7 8a1 1 0 012 0v4a1 1 0 11-2 0V8zm5-1a1 1 0 00-1 1v4a1 1 0 102 0V8a1 1 0 00-1-1z"
                  clip-rule="evenodd"
                ></path>
              </svg>
              暂停
            </button>

            <button class="btn btn-primary" id="showDataBtn" disabled>
              <svg class="icon" fill="currentColor" viewBox="0 0 20 20">
                <path
                  fill-rule="evenodd"
                  d="M3 17a1 1 0 011-1h12a1 1 0 110 2H4a1 1 0 01-1-1zM6.293 6.707a1 1 0 010-1.414l3-3a1 1 0 011.414 0l3 3a1 1 0 01-1.414 1.414L11 5.414V13a1 1 0 11-2 0V5.414L7.707 6.707a1 1 0 01-1.414 0z"
                  clip-rule="evenodd"
                ></path>
              </svg>
              下载数据
            </button>
          </div>

          <div
            class="replay-container"
            id="replayContainer"
            style="display: none"
          >
            <div id="replayTarget" class="replay-target"></div>
          </div>
        </div>

        <!-- 操作演示区域 -->
        <div class="section">
          <h2>🎮 操作演示区域</h2>
          <div class="status">在此区域进行各种操作来测试录制功能</div>

          <!-- 视频播放区域 -->
          <div class="demo-area">
            <h3>📹 本地视频播放</h3>
            <div class="video-controls">
              <input
                type="file"
                id="videoFile"
                accept="video/*"
                class="file-input"
              />
              <label for="videoFile" class="btn btn-primary">
                <svg class="icon" fill="currentColor" viewBox="0 0 20 20">
                  <path
                    fill-rule="evenodd"
                    d="M3 17a1 1 0 011-1h12a1 1 0 110 2H4a1 1 0 01-1-1zM6.293 6.707a1 1 0 010-1.414l3-3a1 1 0 011.414 0l3 3a1 1 0 01-1.414 1.414L11 5.414V13a1 1 0 11-2 0V5.414L7.707 6.707a1 1 0 01-1.414 0z"
                    clip-rule="evenodd"
                  ></path>
                </svg>
                选择视频文件
              </label>
            </div>
            <video
              id="demoVideo"
              controls
              style="
                width: 100%;
                max-width: 600px;
                margin-top: 15px;
                border-radius: 8px;
                display: none;
              "
            >
              您的浏览器不支持视频播放
            </video>
          </div>

          <!-- 交互操作区域 -->
          <div class="demo-area">
            <h3>🖱️ 交互操作测试</h3>
            <div class="interactive-controls">
              <button class="btn btn-success" id="testBtn1">
                点击测试按钮
              </button>
              <button class="btn btn-warning" id="testBtn2">
                悬停效果测试
              </button>
              <button class="btn btn-danger" id="testBtn3">长按测试</button>
            </div>

            <div class="input-area">
              <input
                type="text"
                id="testInput"
                placeholder="在此输入文字测试..."
                class="test-input"
              />
              <textarea
                id="testTextarea"
                placeholder="多行文本输入测试..."
                class="test-textarea"
              ></textarea>
            </div>

            <div class="checkbox-area">
              <label class="checkbox-label">
                <input type="checkbox" id="testCheck1" /> 复选框选项 1
              </label>
              <label class="checkbox-label">
                <input type="checkbox" id="testCheck2" /> 复选框选项 2
              </label>
              <label class="radio-label">
                <input type="radio" name="testRadio" value="option1" /> 单选选项
                1
              </label>
              <label class="radio-label">
                <input type="radio" name="testRadio" value="option2" /> 单选选项
                2
              </label>
            </div>

            <div class="select-area">
              <select id="testSelect" class="test-select">
                <option value="">请选择选项...</option>
                <option value="option1">选项 1</option>
                <option value="option2">选项 2</option>
                <option value="option3">选项 3</option>
              </select>
            </div>

            <div class="scroll-area" id="scrollArea">
              <h4>滚动测试区域</h4>
              <p>这是一个可滚动的区域，用于测试滚动事件的录制。</p>
              <p>内容 1 - 滚动测试内容</p>
              <p>内容 2 - 滚动测试内容</p>
              <p>内容 3 - 滚动测试内容</p>
              <p>内容 4 - 滚动测试内容</p>
              <p>内容 5 - 滚动测试内容</p>
              <p>内容 6 - 滚动测试内容</p>
              <p>内容 7 - 滚动测试内容</p>
              <p>内容 8 - 滚动测试内容</p>
              <p>内容 9 - 滚动测试内容</p>
              <p>内容 10 - 滚动测试内容</p>
            </div>

            <div class="drag-area">
              <div class="draggable-item" id="dragItem" draggable="true">
                🎯 拖拽我进行测试
              </div>
              <div class="drop-zone" id="dropZone">📦 拖拽目标区域</div>
            </div>
          </div>

          <!-- 操作反馈区域 -->
          <div class="demo-area">
            <h3>📊 操作反馈</h3>
            <div id="operationLog" class="operation-log">
              <p>操作日志将在此显示...</p>
            </div>
          </div>
        </div>

        <!-- 技术说明 -->
        <div class="tech-notes">
          <h3>🔧 技术说明</h3>
          <ul>
            <li>
              <strong>rrweb技术</strong>:
              使用开源的rrweb库实现DOM级别的录制和回放
            </li>
            <li>
              <strong>无感知录制</strong>:
              不影响页面性能，记录所有用户交互和DOM变化
            </li>
            <li>
              <strong>完整回放</strong>:
              支持鼠标移动、点击、滚动、输入等所有操作的精确回放
            </li>
            <li>
              <strong>隐私保护</strong>: 支持敏感信息遮罩，保护用户隐私数据
            </li>
            <li><strong>跨浏览器</strong>: 兼容现代浏览器，支持移动端设备</li>
          </ul>
        </div>
      </div>
    </div>

    <!-- 引入rrweb库 - 使用CDN版本 -->
    <script src="./rrweb/rrweb.min.js"></script>
    <script src="./rrweb/index.js"></script>
    <link rel="stylesheet" href="./rrweb/style.css" />
    <!-- 引入录制工具类 -->
    <script src="./rrweb/recorder.js"></script>
    <script>
      /**
       * 页面初始化脚本
       * 引入外部录制工具类后的简化初始化代码
       */

      /**
       * 页面加载完成后初始化录制器
       */
      document.addEventListener('DOMContentLoaded', async () => {
        try {
          console.log('页面DOM加载完成，开始初始化会话录制器...')

          // 创建会话录制器实例
          window.sessionReplayRecorder = new SessionReplayRecorder()
          console.log('Session Replay 录制器初始化成功')
        } catch (error) {
          console.error('Session Replay 录制器初始化失败:', error)

          const errorMsg = `录制器初始化失败：\n\n${error.message}\n\n可能的解决方案：\n1. 检查网络连接\n2. 刷新页面重试\n3. 检查浏览器控制台获取详细错误信息`
          alert(errorMsg)

          const recordStatus = document.getElementById('recordStatus')
          if (recordStatus) {
            recordStatus.className = 'status'
            recordStatus.textContent = '❌ 初始化失败 - ' + error.message
          }
        }
      })
    </script>
  </body>
</html>
